namespace Tombstoner.ViewModel
{
    using System;
    using System.Collections.Generic;

    using GalaSoft.MvvmLight.Messaging;

    using Microsoft.Phone.Shell;

    /// <summary>
    /// This class contains static references to all the view models in the
    /// application and provides an entry point for the bindings.
    /// </summary>
    public sealed class ViewModelLocator : IDisposable
    {
        internal sealed class ViewModelInstance
        {
            public ViewModelBaseWp7 ViewModel { get; private set; }

            public ViewModelInstance(ViewModelBaseWp7 viewModel)
            {
                this.ViewModel = viewModel;

                if (PhoneApplicationService.Current.StartupMode == StartupMode.Activate)
                {
                    this.ViewModel.Activate();
                }

                PhoneApplicationService.Current.Deactivated += this.HandleDeactivation;
            }

            private void HandleDeactivation(object s, DeactivatedEventArgs e)
            {
                this.ViewModel.Deactivate();
            }
        }

        #region Constants and Fields

        private BootStrapper bootStrapper;

        private bool disposed;

        private IDictionary<Type, ViewModelInstance> resolvedViewInstances = new Dictionary<Type, ViewModelInstance>();

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        public ViewModelLocator()
        {
            this.bootStrapper = new BootStrapper();
        }

        #endregion

        #region Properties

        public MainViewModel MainViewModel
        {
            get
            {
                return ResolveInstance<MainViewModel>();
            }
        }

        #endregion

        #region Public Methods

        #endregion

        #region Implemented Interfaces

        #region IDisposable

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (this.resolvedViewInstances != null)
            {
                this.resolvedViewInstances.Clear();
                this.resolvedViewInstances = null;
            }

            if (this.bootStrapper != null)
            {
                this.bootStrapper.Dispose();
                this.bootStrapper = null;
            }
        }

        #endregion

        #endregion

        #region Methods

        /// <summary>
        /// The dispose.
        /// </summary>
        /// <param name="disposing">
        /// The disposing.
        /// </param>
        public void Dispose(bool disposing)
        {
            if (this.disposed)
            {
                return;
            }

            if (disposing)
            {
                this.resolvedViewInstances.Clear();
                this.resolvedViewInstances = null;

                this.bootStrapper.Dispose();
            }

            this.disposed = true;
        }

        private T ResolveInstance<T>() where T : ViewModelBaseWp7
        {
            if (this.resolvedViewInstances.ContainsKey(typeof(T)))
            {
                return (T)this.resolvedViewInstances[typeof(T)].ViewModel;
            }

            var viewModel = this.bootStrapper.Container.Resolve<T>();
            this.resolvedViewInstances.Add(viewModel.GetType(), new ViewModelInstance(viewModel));

            return viewModel;
        }

        #endregion
    }
}